#pragma once

#include <disco.h>
#include <client.h>
#include <siprofileft.h>
#include <bytestreamdatahandler.h>
#include <siprofilefthandler.h>
#include <socks5bytestreamserver.h>
#include <mutex.h>

using namespace gloox;

#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <string>
#include <fstream>
#include <ios>
#include <map>

#include <windows.h>
#include "XepdtThread.h" 
#include "xepdt.h"

class XEPDT_API CXepdtFT: public SIProfileFTHandler, public BytestreamDataHandler
{
public:
	CXepdtFT(Client * client_);
	~CXepdtFT();

	void startSock5Server(int port);

	bool ibbSendFile(const std::string& to, const std::string& file, const std::string& desc, std::string& sid);
	bool sock5SendFile(const std::string& to, const std::string& file, const std::string& desc, std::string& sid);
	std::string getSid(){ return m_sid;}
	SOCKS5BytestreamServer* getSock5Server() {return  m_server;}

	bool isIBBReceiving(){return recvfile != NULL;}

	void setCurrentTestPlanName(const std::string& desc);
	void setCurrentDataFileName(const std::string& desc);

	void SetTransferHandler(const TransferHandler& fDoTransfer);

private:
	void* CXepdtFT::loopSend(void* );
	void* CXepdtFT::loopRecv(void* );

	bool isSend(Bytestream* bs);
	virtual void handleFTRequest( const JID& from, const JID& to, const std::string& sid,
                                    const std::string& name, long size, const std::string& hash,
                                    const std::string& date, const std::string& mimetype,
                                    const std::string& desc, int stypes );

	virtual void handleFTRequestError(const IQ & iq, const std::string & sid);

	virtual void handleFTBytestream(Bytestream * bs);

	virtual const std::string handleOOBRequestResult( const JID& from, const JID& to, const std::string& sid )
	{
		return std::string();
	};

	virtual void handleBytestreamData(Bytestream * bs, const std::string & data);

	virtual void handleBytestreamError(Bytestream * bs, const IQ & stanza);
	virtual void handleBytestreamOpen(Bytestream * bs);
	virtual void handleBytestreamClose(Bytestream * bs);

private:
	Client*       m_client;
	SIProfileFT * m_ft;
	TransferHandler  m_fDoTransfer;
	
	/** lock while sending file in ibb mode */
	util::Mutex   m_ibbSend;
	util::Mutex   m_s5bSendLock;
	util::Mutex   m_s5bRecvLock;
	bool		  m_waitingSendLock;
	bool		  m_waitingRecvLock;
	SOCKS5BytestreamServer *   m_server;
	Bytestream*                m_bsSend;
	Bytestream*                m_bsRecv;

	std::fstream*              recvfile;
	std::wstring			   m_testplanPath;
	std::wstring			   m_currentTestPlanName;
	std::wstring			   m_datafilePath;
	std::wstring			   m_currentDataFileName;
	std::string				   m_sid;

	struct FILEINFO
	{
		int size;
		int transfered;
		Bytestream* bs;
		std::fstream* fileStream;
		string filename;
	};
	typedef std::map<std::string , FILEINFO> FILELIST;
	FILELIST m_rfilelist;
	FILELIST m_sfilelist;

	volatile bool SENDING_THREAD_RUNNING;
	volatile bool RECEIVE_THREAD_RUNNING;

	XepdtThread< CXepdtFT > recvThread;
	XepdtThread< CXepdtFT > sendThread;
};

